#pragma once
#include "Tcpserve.hpp"
#include <memory>
#include "Socket.hpp"
#include <unordered_map>
#include <sstream>
#include <functional>
#include "Util.hpp"
using namespace SocketModule;
using namespace LogModule;

const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";

const std::string webroot = "./webroot";
const std::string homepage = "index.html";
const std::string page_404 = "/404.html";

class HttpRequest
{
public:
    HttpRequest()
        : _is_interact(false) {};

    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }
    std::string Serialize() {};
    bool Deserialize(std::string &reqstr)
    {

        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::INFO) << reqline;
        std::cout << "\n";

        ParseReqLine(reqline);

        LOG(LogLevel::DEBUG) << "METHOD:" << _method;
        LOG(LogLevel::DEBUG) << "URL:" << _uri;
        LOG(LogLevel::DEBUG) << "VERSION:" << _version;

        if (_uri == "/")
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;

        std::string temp = "?";
        auto pos = _uri.find(temp);
        if (pos == std::string::npos)
            return true;

        _args = _uri.substr(pos + temp.size());
        _uri = _uri.substr(0, pos);
        _is_interact = true;
        return res;
    };
    ~HttpRequest() {};

private:
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _header;
    std::string _blankline;
    std::string _text;

    std::string _args;
    bool _is_interact;

public:
    std::string URI() { return _uri; }
    bool IsInteract() { return _is_interact; }
    std::string Args(){ return _args; }
};

class HttpResponse
{
public:
    HttpResponse()
        : _blankline(glinespace),
          _version("HTTP/1.0") {};

    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        std::string resp_header;
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }
        return std::string(status_line + resp_header + _blankline + _text);
    };

    std::string Deserialize(std::string &reqstr) {};

public:
    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;
    // 其余资源
    std::string _targetfile;

public:
    void SetText(std::string text)
    {
        _text=text;
    }
    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }
    void SetCode(const int code)
    {
        _code = code;
        switch (code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "NOT DOUND";
            break;
        case 302:
            _desc = "See Other";
            break;
        default:
            _desc = "error";
            break;
        }
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        auto itor = _headers.find(key);
        if (itor != _headers.end())
            return;
        _headers.insert(std::make_pair(key, value));
    }

    std::string UritoSuffix(const std::string &targetname)
    {
        auto pos = targetname.rfind(".");
        if (pos == std::string::npos)
        {
            return "text/html";
        }
        std::string suffix = targetname.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == ".mp4")
            return "video/mpeg4";
        else if (suffix == ".css")
            return "text/css";
        else if (suffix == ".ico")
            return "image/x-icon";
        else if (suffix == ".png")
            return "image/png";
    }

    bool MakeResponse()
    {

        if (_targetfile == "./webroot/redir")
        {
            SetCode(302);
            SetHeader("Location", "https://www.qq.com/");
            return true;
        };

        LOG(LogLevel::DEBUG) << "用户请求:" << _targetfile;
        bool res = Util::ReadFileContent(_targetfile, &_text);

        int filesize = 0;
        if (!res)
        {
            SetCode(404);
            _targetfile = webroot + page_404;
            std::string suffix = UritoSuffix(_targetfile);
            SetHeader("Content-Type", suffix);
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
        }
        else
        {
            SetCode(200);
            filesize = Util::FileSize(_targetfile);

            std::string suffix = UritoSuffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Set-Cookie","username=zhangsan");
            
        }
        SetHeader("Content-Length", std::to_string(filesize));
        return true;
    }
};

using http_func_t = std::function<void(HttpRequest &req, HttpResponse &resp)>;
class Http
{
public:
    Http(uint16_t port)
        : tsvr(std::make_unique<Tcpserve>(port))
    {
    }

    void HandlerHttpRequest(std::shared_ptr<Socket> &socket, InetAddr &addr)
    {
        // 收到请求，大概率是完整字符串，以字节流形式
        std::string httpreqstr;
        int n = socket->Recv(&httpreqstr);
        // 需要对报文完整性进行审核,暂省略

        std::cout << httpreqstr;
        if (n > 0)
        {
            HttpRequest req;
            req.Deserialize(httpreqstr);
            if (req.IsInteract())
            {
                HttpResponse resp;
                if (_handlers.find(req.URI()) == _handlers.end())
                {
                }
                else
                {
                    _handlers[req.URI()](req, resp);

                    std::string send_str = resp.Serialize();
                    socket->Send(send_str);
                }
            }
            else
            {
                HttpResponse resp;
                resp.SetTargetFile(req.URI());
                if (resp.MakeResponse())
                {
                    std::string send_str = resp.Serialize();
                    socket->Send(send_str);
                }
            }
        }

// #ifndef DEBUG
// #define DEBUG
#ifdef DEBUG
        std::string httpreqstr;
        socket->Recv(&httpreqstr);
        std::cout << httpreqstr;

        HttpResponse resp;
        resp._version = "HTTP/1.1";
        resp._code = 200;
        std::string resoce = webroot + homepage;
        bool res = Util::ReadFileContent(resoce, &resp._text);
        (void)res;
        std::string send_str = resp.Serialize();
        socket->Send(send_str);

#endif
    }

    void Start()
    {
        tsvr->Start([this](std::shared_ptr<Socket> &socket, InetAddr &addr)
                    { this->HandlerHttpRequest(socket, addr); });
    }
    ~Http() {}

    void RegisterServe(const std::string name, http_func_t rout)
    {
        std::string key = webroot + name;
        auto itor = _handlers.find(name);
        if (itor == _handlers.end())
        {
            _handlers.insert(std::make_pair(key, rout));
        }
    };

private:
    std::unique_ptr<Tcpserve> tsvr;
    std::unordered_map<std::string, http_func_t> _handlers;
};